#include<iostream>
using namespace std;
#include"Log.hpp"
#include"Socket.hpp"
#include<sys/select.h>
#include<sys/time.h>

int defaultport = 8080;

class SelectServer
{
public:
    SelectServer(uint16_t port = defaultport) 
    :    port_(port)
    {}
    ~SelectServer()
    {
        listensock_.Close();
    }

    bool Init()
    {
        listensock_.InitSocket();
        listensock_.Bind(port_);
        listensock_.Listen(); 
    }
    //
    void HanderEvent(fd_set& rfds)
    {
        if (FD_ISSET(listensock_.Fd(), &rfds))
        {
            //我们连接的事件就绪了。
            string clientip;
            uint16_t clientport = 0;
            int sock = listensock_.Accept(&clientip, &clientport);   //获取的时候会不会阻塞在这里？不会，因为上层已经告诉我们就绪了。
            if (sock < 0) 
            {
                return ;
            }
            else
            {
                lg(Info, "accept success!!!");
                
                //建立好了连接之后， 可以直接读吗？ 不可以。 因为我们这是单进程。如果这里读， 那么其他的就绪的套接字就被阻塞了。
            }
        }
    }
    //
    void Start()
    {
        int listensock = listensock_.Fd();
        for(;;)
        {
            //accept不知能直接accept。 因为accept就是在检测listensock上面的事件, 但是一检测， 如果对方没有connect， 那么就阻塞住了， 我还怎么继续下去呢？
            //这里的新连接到来是什么呢？ 新连接到来其实就相当于读事件就绪。
            fd_set rfds;
            FD_ZERO(&rfds);
            FD_SET(listensock, &rfds);
            fd_set wfds;
            struct timeval timeout = {5, 0};  // 输入输出，可能要进行周期的重复设置。   
            int n = select(listensock + 1, &rfds, nullptr, nullptr, &timeout);  //如果事件就绪，上层不处理，select会一直通知你。所以就要处理
            //如果select告诉你就绪了，接下来的一次读取，我们读取fd的时候， 不会被阻塞。因为底层数据已经就绪了。 我们不需要等了， 只需要读
            switch(n)
            {
                case 0:
                    cout << "time out, timeout: " << timeout.tv_sec << "." << timeout.tv_sec << endl;
                    break;
                case -1:
                    cerr << "select error" << endl;
                    break;
                default:
                    //有时间就绪了,TOOD
                    cout << "get a link!!!" << endl;
                    HanderEvent(rfds);
                    //处理
                    break;   
            }
        }   
    }

private:
    Socket listensock_;
    uint16_t port_;
};